/*
 Copyright (c) 2009 Rafal Szemraj - http://szemraj.eu

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 of the Software, and to permit persons to whom the Software is furnished to do so,
 subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all 
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
 FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
*/
package eu.szemraj.geom {
    import flash.display.Stage;    
    import flash.display.DisplayObjectContainer;   
    import flash.display.DisplayObject;   
    import flash.geom.Point;

    /**
     * This class is basic extension for core Point class
     */
    public class Vector2D extends Point {

        /**
         * Creates Vector instances from Point instance
         * @param p Point instance
         * @return
         */
        public static function fromPoint( p:Point ):Vector2D {
   		
            return new Vector2D( p.x, p.y );	
        }

        public static function getDisplayObjectCenter( displayObject:DisplayObject ):Vector2D {
      	
      		return Vector2D.getDisplayObjectSize(displayObject).scaleNew( .5 );
        }
        
        public static function getDisplayObjectSize( displayObject:DisplayObject ):Vector2D {
      	
      		var w:Number;
      		var h:Number;
            if( displayObject is Stage ) {
            	
                w = ( displayObject as Stage ).stageWidth;
                h = ( displayObject as Stage ).stageHeight;
            }
            else {
            	
            	w = displayObject.width;
      			h = displayObject.height;
            }
            return new Vector2D( w, h );
        }

        /**
         * @param x x vector coordinate         * @param y y vector coordinate
         */        public function Vector2D(x:Number = 0, y:Number = 0) {
            super( x, y );
        }

        /**
         * Scales vector by given value
         * @param scaleValue value of scale
         */        public function scale( scaleValue:Number ):void {
      	
            x *= scaleValue;
            y *= scaleValue;	
        }

        /**
         * Scales vector by given value and return new Vector instances ( original vector is not modified )
         * @param scaleValue value of scale
         */        public function scaleNew( scaleValue:Number ):Vector2D {
      	
            var vc:Vector2D = getClone( );
            vc.scale( scaleValue );
            return vc;	
        }

        /**
         * Substract vector from given instance
         * @param v vector to substract
         */
        public function minus( v:Vector2D ):void {
      	
            x -= v.x;
            y -= v.y;	
        }

        /**
         * Substracts vector from given instance and return new Vector instances ( original vector is not modified )
         * @param v vector to substract
         */
        public function minusNew( v:Vector2D ):Vector2D {
      	
            var vc:Vector2D = getClone( );
            vc.x -= v.x;
            vc.y -= v.y;
            return vc;
        }

        /**
         * Adds vector from given instance
         * @param v vector to substract
         */
        public function plus( v:Vector2D ):void {
      
            x += v.x;
            y += v.y;	
        }

        /**
         * Adds vector from given instance and return new Vector instances ( original vector is not modified )
         * @param v vector to substract
         */
        public function plusNew( v:Vector2D ):Vector2D {
      	
            var vc:Vector2D = getClone( );
            vc.x += v.x;
            vc.y += v.y;
            return vc;
        }

        /**
         * Returns clon of Vector instances
         */
        public function getClone():Vector2D {
      	
            return new Vector2D( x, y );	
        }

        /**
         * Returns vector translated form given coordinates to global coordinates
         * @param localCoordinates coordinates container
         * @see #toOtherCoordinates
         */
        public function toGlobalCoordinates( localCoordinates:DisplayObject ):void {
      	
            var p:Point = localCoordinates.localToGlobal( this );
            x = p.x;
            y = p.y;
        }

        public function toGlobalCoordinatesNew( localCoordinates:DisplayObject ):Vector2D {
      	
            var p:Point = localCoordinates.localToGlobal( this );
            return fromPoint( p );
        }
        
        /**
         * Returns vector translated form one coordinates to other coordinates
         * @param localCoordinates source coordinates container
         * @param otherCoordinates destination coordinates container
         * @see #toGlobalCoordinates
         */
        public function toOtherCoordinates( localCoordinates:DisplayObject, otherCoordinates:DisplayObject ):void {
      	
            var globalPoint:Vector2D = toGlobalCoordinatesNew( localCoordinates );
            var p:Point = otherCoordinates.globalToLocal( globalPoint );
            x = p.x;
            y = p.y;	
        }
        
        /**
         * Returns vector translated form one coordinates to other coordinates
         * @param localCoordinates source coordinates container
         * @param otherCoordinates destination coordinates container
         * @see #toGlobalCoordinates
         */
        public function toOtherCoordinatesNew( localCoordinates:DisplayObject, otherCoordinates:DisplayObject ):Vector2D {
      	
            var globalPoint:Vector2D = toGlobalCoordinatesNew( localCoordinates );
            var p:Point = otherCoordinates.globalToLocal( globalPoint );
            return fromPoint( p );	
        }
        
         /**
         * Returns vector translated form given coordinates to global coordinates
         * @param localCoordinates coordinates container
         * @see #toOtherCoordinates
         */
        public function fromGlobalCoordinates( localCoordinates:DisplayObjectContainer ):void {
      	
            var p:Point = localCoordinates.globalToLocal( this );
            x = p.x;
            y = p.y;
        }

        public function fromGlobalCoordinatesNew( localCoordinates:DisplayObjectContainer ):Vector2D {
      	
            var p:Point = localCoordinates.globalToLocal( this );
            return fromPoint( p );
        }

        /**
         * Sets vector angle
         * @param value angle value
         */
        public function set angle( value:Number ):void {
      	
            var r:Number = length;
            x = r * Trigo.cosD( value );
            y = r * Trigo.sinD( value );
        }

        /**
         * Returns vector angle value
         */
        public function get angle():Number {
      
            return Trigo.atan2D( y, x );
        }

        /**
         * Rounds vector coordinates to given decimal places
         * @param decimalPlaces number of decimal places after round operation
         */
        public function roundTo( decimalPlaces:int = 0 ):void {
      	
            var n:Number = Math.pow( 10, decimalPlaces );
            x = Math.round( x * n ) / n;
            y = Math.round( y * n ) / n;
        }

        /**
         * Rounds vector coordinates to given decimal places
         * @param decimalPlaces number of decimal places after round operation
         * @return vector instances with rounded coordinates
         */
        public function roundToNew( decimalPlaces:int = 0 ):Vector2D {
      	
            var v:Vector2D = getClone( );
            v.roundTo( decimalPlaces );
            return v;
        }


        /**
         * Compares two vectors. Vectors are equal if their coordinates are the same
         * @param vector another vector to compare
         * @return true if vectors are the same, otherwise false
         */
        public function compareTo( vector:Vector2D ):Boolean {
      	
            return vector.x == x && vector.y == y;
        }

        /**
         * Returns string representation of vector
         */
        override public function toString():String {
      	
            return "[ " + x + " ," + y + " ]";	
        }
    }
}
